package br.com.fogas.impressora;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import br.com.fogas.database.entidade.Cliente;
import br.com.fogas.database.entidade.NotaFiscal;
import br.com.fogas.utils.FogasUtility;
import br.com.fogas.utils.StringUtility;

public class ImpressaoBoletoBuilder {

	private String nomeBanco = StringUtility.EMPTY;
	private String codBanco = StringUtility.EMPTY;
	private String linhaDigitavel = StringUtility.EMPTY;
	private String localPagamento = StringUtility.EMPTY;
	private String localOpcionalPagamento = StringUtility.EMPTY;
	private String vencimento = StringUtility.EMPTY;
	private String cedente = StringUtility.EMPTY;
	private String agenciaCodigoCedente = StringUtility.EMPTY;
	private String datadocumento = StringUtility.EMPTY;
	private String numeroDocumento = StringUtility.EMPTY;
	private String especieDoc = StringUtility.EMPTY;
	private String aceite = StringUtility.EMPTY;
	private String dataProcessameto = StringUtility.EMPTY;
	private String nossoNumero = StringUtility.EMPTY;
	private String usoDoBanco = StringUtility.EMPTY;
	private String cip = StringUtility.EMPTY;
	private String carteira = StringUtility.EMPTY;
	private String especieMoeda = StringUtility.EMPTY;
	private String quantidade = StringUtility.EMPTY;
	private String valor = StringUtility.EMPTY;
	private String valorDocumento = StringUtility.EMPTY;
	private String desconto = StringUtility.EMPTY;
	private String deducoes = StringUtility.EMPTY;
	private String multa = StringUtility.EMPTY;
	private String acrescimos = StringUtility.EMPTY;
	private String valorCobrado = StringUtility.EMPTY;
	private String sacadoNome = StringUtility.EMPTY;
	private String sacadoEndereco = StringUtility.EMPTY;
	private String sacadoCep = StringUtility.EMPTY;
	private String sacadoCidade = StringUtility.EMPTY;
	private String sacadoUF = StringUtility.EMPTY;
	private String sacadoCnpj = StringUtility.EMPTY;
	private String autentificacao = StringUtility.EMPTY;
	private String fichaCompensacao = StringUtility.EMPTY;
	private String numeroCodBarras = StringUtility.EMPTY;
	private List<String> instrucoesCedente = new ArrayList<String>();
	
	private ImpressoraMPT_Builder impressoraBuilder;
	
	public ImpressaoBoletoBuilder(ImpressoraMPT_Builder impressoraBuilder) {
		this.impressoraBuilder = impressoraBuilder;
	}

	public ImpressaoBoletoBuilder nomeBanco(String nomeBanco) {
		this.nomeBanco = nomeBanco;
		return this;
	}

	public ImpressaoBoletoBuilder codBanco(String codBanco) {
		this.codBanco = codBanco;
		return this;
	}

	public ImpressaoBoletoBuilder linhaDigitavel(String linhaDigitavel) {
		linhaDigitavel = FogasUtility.fogasBoleto.mascaraLinhaDigitavelBoleto(linhaDigitavel);
		this.linhaDigitavel = linhaDigitavel;
		this.numeroCodBarras = calcularCodigoBarra(linhaDigitavel);
		return this;
	}

	public ImpressaoBoletoBuilder localPagamento(String localPagamento) {
		this.localPagamento = localPagamento;
		return this;
	}

	public ImpressaoBoletoBuilder localOpcionalPagamento(
			String localOpcionalPagamento) {
		this.localOpcionalPagamento = localOpcionalPagamento;
		return this;
	}

	public ImpressaoBoletoBuilder vencimento(Date vencimento) {
		this.vencimento = FogasUtility.data.getStringByDateAndFormat(vencimento, "dd/MM/yyyy");
		return this;
	}

	public ImpressaoBoletoBuilder cedente(String cedente) {
		this.cedente = cedente;
		return this;
	}

	public ImpressaoBoletoBuilder agenciaCodigoCedente(
			String agenciaCodigoCedente) {
		this.agenciaCodigoCedente = agenciaCodigoCedente;
		return this;
	}

	public ImpressaoBoletoBuilder dataDocumento(Date dataDocumento) {
		this.datadocumento =  FogasUtility.data.getStringByDateAndFormat(dataDocumento, "dd/MM/yyyy");
		return this;
	}

	public ImpressaoBoletoBuilder numeroDocumento(NotaFiscal notaFiscal) {
		this.numeroDocumento = notaFiscal.getTx_nfnum()+"-"+notaFiscal.getTx_serie();
		return this;
	}

	public ImpressaoBoletoBuilder especieDoc(String especieDoc) {
		this.especieDoc = especieDoc;
		return this;
	}

	public ImpressaoBoletoBuilder aceite(String aceite) {
		this.aceite = aceite;
		return this;
	}

	public ImpressaoBoletoBuilder dataProcessameto(Date dataProcessameto) {
		this.dataProcessameto = FogasUtility.data.getStringByDateAndFormat(dataProcessameto, "dd/MM/yyyy");
		return this;
	}

	public ImpressaoBoletoBuilder nossoNumero(String nossoNumero) {
		//09000000061576
		//09/00003742138-6
		String numero = StringUtility.EMPTY;
		numero += StringUtility.substring(nossoNumero, 0, 2) + "/";
		numero += StringUtility.substring(nossoNumero, 2, 13)+ "-";
		numero += StringUtility.substring(nossoNumero, 13, 14);
		this.nossoNumero = numero;
		return this;
	}

	public ImpressaoBoletoBuilder usoDoBanco(String usoDoBanco) {
		this.usoDoBanco = usoDoBanco;
		return this;
	}

	public ImpressaoBoletoBuilder cip(String cip) {
		this.cip = cip;
		return this;
	}

	public ImpressaoBoletoBuilder carteira(String carteira) {
		this.carteira = carteira;
		return this;
	}

	public ImpressaoBoletoBuilder especieMoeda(String especieMoeda) {
		this.especieMoeda = especieMoeda;
		return this;
	}

	public ImpressaoBoletoBuilder quantidade(String quantidade) {
		this.quantidade = quantidade;
		return this;
	}

	public ImpressaoBoletoBuilder valor(double valor) {
		String vlBoleto = FogasUtility.string.currencyFormat(valor);
		this.valor = StringUtility.replace(vlBoleto, "R$", "");
		return this;
	}

	public ImpressaoBoletoBuilder valorDocumento(double valorDocumento) {
		String vlBoleto = FogasUtility.string.currencyFormat(valorDocumento);
		this.valorDocumento = StringUtility.replace(vlBoleto, "R$", "");
		return this;
	}

	public ImpressaoBoletoBuilder desconto(String desconto) {
		this.desconto = desconto;
		return this;
	}

	public ImpressaoBoletoBuilder deducoes(String deducoes) {
		this.deducoes = deducoes;
		return this;
	}

	public ImpressaoBoletoBuilder multa(String multa) {
		this.multa = multa;
		return this;
	}

	public ImpressaoBoletoBuilder acrescimos(String acrescimos) {
		this.acrescimos = acrescimos;
		return this;
	}

	public ImpressaoBoletoBuilder valorCobrado(String valorCobrado) {
		this.valorCobrado = valorCobrado;
		return this;
	}

	public ImpressaoBoletoBuilder sacadoNome(Cliente sacado) {
		String nome = new StringBuilder()
		.append(StringUtility.removeZeroEsquerdaString(sacado.getTx_cod_cliente()))
		.append(" - ")
		.append(sacado.getTx_nome())
		.toString();
		this.sacadoNome = nome;
		return this;
	}

	public ImpressaoBoletoBuilder sacadoEndereco(Cliente sacado) {
		this.sacadoEndereco = sacado.getTx_endereco();
		return this;
	}

	public ImpressaoBoletoBuilder sacadoCep(Cliente sacado) {
		this.sacadoCep = sacado.getTx_cod_postal();
		return this;
	}

	public ImpressaoBoletoBuilder sacadoCidade(Cliente sacado) {
		this.sacadoCidade = sacado.getTx_cidade();
		return this;
	}

	public ImpressaoBoletoBuilder sacadoUF(Cliente sacado) {
		this.sacadoUF = sacado.getTx_regiao();
		return this;
	}

	public ImpressaoBoletoBuilder sacadoCnpj(Cliente sacado) {
		this.sacadoCnpj = FogasUtility.string.cnpjFormatado(sacado.getTx_cnpj());
		return this;
	}

	public ImpressaoBoletoBuilder autentificacao(String autentificacao) {
		this.autentificacao = autentificacao;
		return this;
	}

	public ImpressaoBoletoBuilder fichaCompensacao(String fichaCompensacao) {
		this.fichaCompensacao = fichaCompensacao;
		return this;
	}

	public ImpressaoBoletoBuilder numeroCodBarras(String numeroCodBarras) {
		this.numeroCodBarras = numeroCodBarras;
		return this;
	}
	
	public ImpressaoBoletoBuilder instrucaoCedente(String instrucao) {
		if(this.instrucoesCedente.size() == 7) {
			throw new IllegalArgumentException("maximo 7 linhas de instrucao");
		}
		this.instrucoesCedente.add(instrucao);
		return this;
	}

	public String getNomeBanco() {
		return nomeBanco;
	}

	public String getCodBanco() {
		return codBanco;
	}

	public String getLinhaDigitavel() {
		return linhaDigitavel;
	}

	public String getLocalPagamento() {
		return localPagamento;
	}

	public String getLocalOpcionalPagamento() {
		return localOpcionalPagamento;
	}

	public String getVencimento() {
		return vencimento;
	}

	public String getCedente() {
		return cedente;
	}

	public String getAgenciaCodigoCedente() {
		return agenciaCodigoCedente;
	}

	public String getDatadocumento() {
		return datadocumento;
	}

	public String getNumeroDocumento() {
		return numeroDocumento;
	}

	public String getEspecieDoc() {
		return especieDoc;
	}

	public String getAceite() {
		return aceite;
	}

	public String getDataProcessameto() {
		return dataProcessameto;
	}

	public String getNossoNumero() {
		return nossoNumero;
	}

	public String getUsoDoBanco() {
		return usoDoBanco;
	}

	public String getCip() {
		return cip;
	}

	public String getCarteira() {
		return carteira;
	}

	public String getEspecieMoeda() {
		return especieMoeda;
	}

	public String getQuantidade() {
		return quantidade;
	}

	public String getValor() {
		return valor;
	}

	public String getValorDocumento() {
		return valorDocumento;
	}

	public String getDesconto() {
		return desconto;
	}

	public String getDeducoes() {
		return deducoes;
	}

	public String getMulta() {
		return multa;
	}

	public String getAcrescimos() {
		return acrescimos;
	}

	public String getValorCobrado() {
		return valorCobrado;
	}

	public String getSacadoNome() {
		return sacadoNome;
	}

	public String getSacadoEndereco() {
		return sacadoEndereco;
	}

	public String getSacadoCep() {
		return sacadoCep;
	}

	public String getSacadoCidade() {
		return sacadoCidade;
	}

	public String getSacadoUF() {
		return sacadoUF;
	}

	public String getSacadoCnpj() {
		return sacadoCnpj;
	}

	public String getAutentificacao() {
		return autentificacao;
	}

	public String getFichaCompensacao() {
		return fichaCompensacao;
	}

	public String getNumeroCodBarras() {
		return numeroCodBarras;
	}

	public List<String> getInstrucoesCedente() {
		return instrucoesCedente;
	}
	
	/**
	 * imprimi o boleto com o codigo de barra passando a instancia atual dessa classe
	 * 
	 * @author andre.nascimento
	 */
	public void imprimir() {
		BoletoTemplate boletoTemplate = new BoletoTemplate();
        byte[][] bytes = boletoTemplate.printBoleto(this);
        
        for (int i = 0; i < bytes.length; i++){	            	
        	impressoraBuilder.sendBytes(bytes[i]);
        }
	}
	
	/**
	 * calcula o codigo de barras dado a linha digitavel
	 * 
	 * @param linhaDigitavelBoleto
	 * @return String
	 */
	private String calcularCodigoBarra(String linha) { 
		Pattern regex = Pattern.compile("[^0-9]");  
		Matcher matcher = regex.matcher(linha);  
		StringBuffer tmp = new StringBuffer();
		while(matcher.find()) {  
		   matcher.group();  
		   matcher.appendReplacement(tmp, ""); // AQUI SUBSTITUI ELAS POR ESPAÇOS VAZIOS  
		}  
		// remove caracteres diferente de digitos
		String barra = tmp.toString();//linha.replace("[^0-9]", "");

		// completa com zeros a direita da string
		if (barra.length() < 47) {
			barra = barra + "000000000000000".substring(0, 47 - barra.length());
		}

		barra = barra.substring(0, 4) + barra.substring(32, 47)
				+ barra.substring(4, 9) + barra.substring(10, 20)
				+ barra.substring(21, 31);

		// calcula digito verificador
		//int digito = calcularDigitoModulo11(barra.substring(0, 4) + barra.substring(5, 44));

		// verifica digito

		//if (digito != Integer.valueOf(barra.substring(4, 5))) {
		//	throw new IllegalArgumentException("Digito Verificador incorreto");
		//}

		return barra;
	}
	/*
	public int calcularDigitoModulo11(String numero) {
		int soma = 0;
		int peso = 2;
		int digito;

		for (int i = numero.length() - 1; i >= 0; i--) {

			soma = soma + Integer.valueOf(numero.substring(i, i + 1)) * peso;

			if (peso < 9) {
				peso = peso + 1;
			} else {
				peso = 2;
			}
		}

		digito = 11 - (soma % 11);

		if (digito > 9) {
			digito = 0;
		}

		if (digito == 0) {
			digito = 1;
		}

		return digito;
	}
	*/
}